<?php

class AggregateDefinition extends EntityDefinition implements IAggregateDefinition
{

  /**
   * (non-PHPdoc)
   * @see simplify/kernel/domain/api/IDomObjDefinition#factory()
   * @return IAggregate
   */
  public function factory()
  {
    $class = $this->class;

    if (! class_exists($class)) {
      return new CustomAggregate($class, $this);
    }

    return parent::factory();
  }

  public function factoryObject($type, $name)
  {
    $types = array('hasOne', 'hasMany', 'belongsTo', 'hasAndBelongsToMany');

    if (! in_array($type, $types)) {
      return parent::factoryObject($type, $name);
    }

    $def = null;

    if (isset($this->definitions['connections'][$type])) {
      if (isset($this->definitions['connections'][$type][strtolower($name)])) {
        $def = $this->definitions['connections'][$type][strtolower($name)];
        unset($this->definitions['connections'][$type][strtolower($name)]);
      }
      else {
        foreach ($this->definitions['connections'][$type] as $k => $_def) {
          if (is_string($_def) && $_def == $name || sy_get_param($_def, 'name') == $name) {
            if (is_string($_def)) {
              $_def = array();
            }

            $def = $_def;
            unset($this->definitions['connections'][$type][$k]);
            break;
          }
        }
      }
    }

    if (is_null($def)) {
      throw new DomainException("Domain object definition not found: <b>$name</b>");
    }

    $class = Inflector::camelize($type . 'Association');

    $target = Inflector::singularize($name);

    $assoc = new $class($this, $target, $def);

    return $this->addAssociation($name, $assoc);
  }

  /**
   * (non-PHPdoc)
   * @see simplify/kernel/domain/api/IAggregateDefinition#addAssociation($name, $def)
   */
  public function addAssociation($name, IAssociationDefinition $def)
  {
    if ($this->hasAssociation($name)) {
      throw new DomainException("Duplicate association definition: <b>$name</b>");
    }

    $this->definitions['associations'][strtolower($name)] = $def;

    return $this;
  }

  /**
   * (non-PHPdoc)
   * @see simplify/kernel/domain/api/IAggregateDefinition#getAssociation($name)
   */
  public function getAssociation($name)
  {
    if (! $this->hasAssociation($name)) {
      throw new AssociationNotFoundException("Association not found: <b>$name</b>");
    }

    return $this->definitions['associations'][strtolower($name)];
  }

  /**
   *
   * @return array
   */
  public function getAssociations()
  {
    $types = array('hasOne', 'hasMany', 'belongsTo', 'hasAndBelongsToMany');

    foreach ($types as $type) {
      if (! isset($this->definitions['connections'][$type])) {
        continue;
      }

      foreach ($this->definitions['connections'][$type] as $name => $def) {
        if (! is_string($name)) {
          if (is_string($def)) {
            $name = $def;
          }
          elseif (is_array($def)) {
            $name = sy_get_param($def, 'name');
          }
          else {
            throw new DomainException('Missing association name');
          }
        }

        if (! $this->hasAssociation($name)) {
          $this->factoryObject($type, $name);
        }
      }
    }

    if (! isset($this->definitions['associations'])) {
      $this->definitions['associations'] = array();
    }

    return $this->definitions['associations'];
  }

  /**
   * (non-PHPdoc)
   * @see simplify/kernel/domain/api/IAggregateDefinition#hasAssociation($name)
   */
  public function hasAssociation($name)
  {
    return (isset($this->definitions['associations']) && isset($this->definitions['associations'][strtolower($name)]) && ($this->definitions['associations'][strtolower($name)] instanceof AssociationDefinition));
  }

}

?>